x86: Make offlined CPU enter deepest C state
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 2 Mar 2009 11:11:19 +0000 (11:11 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 2 Mar 2009 11:11:19 +0000 (11:11 +0000)
Before cpuidle is introduced, offlined CPU only enter C1 (by HLT
instruction). This is not optimal since C2/C3 can bring more power
saving. Since now cpuidle is introduced, it is time for offlined CPU
to enter more deeper C state.

This patch add the logic to make offlined CPU enter deepest C state,
if cpuidle is enabled.

Signed-off-by: Yu Ke <ke.yu@intel.com>
Signed-off-by: Wei Gang <gang.wei@intel.com>
Signed-off-by: Tian Kevin <kevin.tian@intel.com>
xen/arch/x86/acpi/cpu_idle.c
xen/arch/x86/domain.c

index b86d622bf9617304426ef8ffabd26d92dfe8895b..45b6eb6456d2070e43dd3f5734be6e0df27214c5 100644 (file)
@@ -55,6 +55,7 @@ static void (*lapic_timer_on)(void);
 
 extern u32 pmtmr_ioport;
 extern void (*pm_idle) (void);
+extern void (*dead_idle) (void);
 
 static void (*pm_idle_save) (void) __read_mostly;
 unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER - 1;
@@ -369,6 +370,43 @@ static void acpi_processor_idle(void)
         cpuidle_current_governor->reflect(power);
 }
 
+static void acpi_dead_idle(void)
+{
+    struct acpi_processor_power *power;
+    struct acpi_processor_cx *cx;
+    int unused;
+
+    if ( (power = processor_powers[smp_processor_id()]) == NULL )
+        goto default_halt;
+
+    if ( (cx = &power->states[power->count-1]) == NULL )
+        goto default_halt;
+
+    for ( ; ; )
+    {
+        if ( !power->flags.bm_check && cx->type == ACPI_STATE_C3 )
+            ACPI_FLUSH_CPU_CACHE();
+
+        switch ( cx->entry_method )
+        {
+            case ACPI_CSTATE_EM_FFH:
+                /* Not treat interrupt as break event */
+                mwait_idle_with_hints(cx->address, 0);
+                break;
+            case ACPI_CSTATE_EM_SYSIO:
+                inb(cx->address);
+                unused = inl(pmtmr_ioport);
+                break;
+            default:
+                goto default_halt;
+        }
+    }
+
+default_halt:
+    for ( ; ; )
+        halt();
+}
+
 static int init_cx_pminfo(struct acpi_processor_power *acpi_power)
 {
     int i;
@@ -740,6 +778,11 @@ long set_cx_pminfo(uint32_t cpu, struct xen_processor_power *power)
         pm_idle_save = pm_idle;
         pm_idle = acpi_processor_idle;
     }
+
+    if ( cpu_id == 0 )
+    {
+        dead_idle = acpi_dead_idle;
+    }
         
     return 0;
 }
index ceda72770141a863f3b36b051444cb8eca81f927..5c89eba7ab0963329eb70299c173069e3227ca1b 100644 (file)
@@ -58,7 +58,9 @@ DEFINE_PER_CPU(u64, efer);
 DEFINE_PER_CPU(unsigned long, cr4);
 
 static void default_idle(void);
+static void default_dead_idle(void);
 void (*pm_idle) (void) = default_idle;
+void (*dead_idle) (void) = default_dead_idle;
 
 static void paravirt_ctxt_switch_from(struct vcpu *v);
 static void paravirt_ctxt_switch_to(struct vcpu *v);
@@ -84,6 +86,12 @@ static void default_idle(void)
         local_irq_enable();
 }
 
+static void default_dead_idle(void)
+{
+    for ( ; ; )
+        halt();
+}
+
 static void play_dead(void)
 {
     /*
@@ -102,8 +110,7 @@ static void play_dead(void)
 
     /* With physical CPU hotplug, we should halt the cpu. */
     local_irq_disable();
-    for ( ; ; )
-        halt();
+    (*dead_idle)();
 }
 
 void idle_loop(void)